Skip to content

fix: 초기 로딩 스켈레톤/무한스크롤 로딩 분리#314

Merged
heeeeyong merged 3 commits intorefactorfrom
refactor-infiniteScroll
Feb 27, 2026
Merged

fix: 초기 로딩 스켈레톤/무한스크롤 로딩 분리#314
heeeeyong merged 3 commits intorefactorfrom
refactor-infiniteScroll

Conversation

@heeeeyong
Copy link
Collaborator

@heeeeyong heeeeyong commented Feb 25, 2026

📝작업 내용

Memory, SearchBook, SavePage, GroupSearch, FollowerListPage, Feed, FeedDetailPage에서 훅 기반 무한스크롤, 기존 수동 페이징, 스켈레톤 로직이 혼재되어 있어 아래 원칙에 따라 코드를 정리했습니다.

  • useInifinieScroll만 남기고 수동 loadMore/observer 제거
  • 스켈레톤은 isLoading && items.length === 0에서만 표시
  • 무한스크롤 추가 로딩(isLoadingMore)에서는 스켈레톤 미사용 (필요시 스피너만 유지)
  • 충돌로 생긴 중복 요청, 미정의 변수, 잘못된 import 정리

수정 파일

  • src/pages/feed/Feed.tsx
    • 섞여 있던 setTabLoading/loadTotalFeeds/loadMyFeeds 경로 제거
    • currentFeed.isLoading && currentFeed.items.length === 0일 때만 초기 스켈레톤
    • 무한스크롤은 useInifinieScroll 결과만 사용
  • src/pages/feed/FeedDetailPage.tsx
    • 중복 호출/깨진 로딩 코드 정리
    • 상세 데이터 초기 로딩만 스켈레톤 유지
  • src/pages/feed/FollowerListPage.tsx
    • 수동 페이징 코드 제거하고 useInifinieScroll로 단일화
    • 초기 진입만 UserProfileItemSkeleton 표시
  • src/pages/groupSearch/GroupSearch.tsx
    • 깨진 검색/페이징 병합 코드 정리
    • 검색 결과도 훅 기반으로 통일
    • 초기 검색 로딩에만 카드 스켈레톤
  • src/pages/memory/Memory.tsx
    • 충돌 상태였던 파일을 전체 정리
    • 초기 진입 시만 RecordItemSkeleton
    • 무한스크롤 시 스켈레톤 재표시 없이 리스트 유지
  • src/pages/mypage/SavePage.tsx
    • 기존 수동 IntersectionObserver/중복 상태 제거
    • 탭별 훅 결과 기준으로 초기 스켈레톤만 표시
  • src/pages/searchBook/SearchBook.tsx
    • 수동 loadFirst/loadMore 제거, 훅 기반으로 통일
    • 초기 피드 로딩에서만 FeedPostSkeleton
    • LoadingBox import 누락 포함 정리

Summary by CodeRabbit

변경 사항

  • 성능 개선

    • 초기 로딩 스켈레톤과 최소 로딩 시간 도입으로 로드 경험 일관화
    • 피드·팔로워·검색·메모리의 무한 스크롤 및 로딩 흐름 최적화
  • 버그 수정

    • 그룹 검색 및 팔로워 목록 에러 처리 강화
    • 메모리 페이지 필터·페이지 범위 및 내비게이션 관련 안정성 개선
  • 리팩토링

    • 페칭 및 로딩 제어 재구성으로 렌더링 분기와 상태 관리 정리
    • 피드 상세 로드 병렬화로 응답 지연 최소화

@heeeeyong heeeeyong self-assigned this Feb 25, 2026
@vercel
Copy link

vercel bot commented Feb 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thip Error Error Feb 27, 2026 11:48am

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Walkthrough

여러 페이지에서 초기/추가 로딩 분리, 최소 로딩 지연 추가, useInfiniteScroll 기반 페이징 도입, 일부 비동기 흐름 병렬화(Promise.all) 및 TotalFeed의 prop 이름(isMyFeedisTotalFeed) 변경이 적용되었습니다.

Changes

Cohort / File(s) Summary
Feed 관련 변경
src/pages/feed/Feed.tsx, src/components/feed/TotalFeed.tsx
초기 로딩 판별용 showInitialLoading 도입으로 렌더 분기 조정; 캐시 쓰기 효과 제거; TotalFeed prop 명칭을 isTotalFeed로 변경해 사용법 정렬.
Feed 상세 페이지
src/pages/feed/FeedDetailPage.tsx
피드 상세 조회와 최소 로딩 지연을 Promise.all로 병렬 대기하도록 변경.
팔로워/팔로잉 리스트
src/pages/feed/FollowerListPage.tsx
기존 페이징 로직을 useInfiniteScroll로 교체; fetchPage 재구성(에러 처리·총합 계산); 초기 스켈레톤 표시 및 minLoadingTime 동기화 추가.
그룹 검색 페이지
src/pages/groupSearch/GroupSearch.tsx
queryTerm 도입 및 검색 상태 기반 useInfiniteScroll 활성화/reloadKey 변경; 빈 쿼리 조기 종료, minLoadingTime 적용, debounced term 초기화/리팩터링.
메모리 페이지
src/pages/memory/Memory.tsx
무한 스크롤·페칭 재구성, 초기 스켈레톤 플래그(showInitialSkeleton) 추가, 최소 로딩 시간 처리, 정수 파싱(radix 10) 일관화, room 상태/페이지 정보 처리 개선.
도서 검색(ISBN)
src/pages/searchBook/SearchBook.tsx
커서 없을 때 500ms 최소 로딩 지연 추가; isbn 부재 시 조기 종료 유지; API 응답 정규화(nextCursor null 보장).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ljh130334
  • ho0010

Poem

🐰 새벽 코드 밭에 파종하듯,
로딩은 다듬고 흐름은 병렬로,
훅은 굴려서 페이지를 늘리고,
토끼는 당근 먹으며 빌드 기다리네.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경사항의 주요 내용을 명확하게 설명합니다. '초기 로딩 스켈레톤/무한스크롤 로딩 분리'는 PR의 핵심인 로딩 상태 분리 리팩토링을 정확히 요약합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-infiniteScroll

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/pages/mypage/SavePage.tsx (1)

38-66: ⚠️ Potential issue | 🟡 Minor

Feed.tsx와 동일하게 minLoadingTime 패턴이 빠져 있습니다. FollowerListPage, SearchBook, Memory 등 다른 페이지에서는 첫 페이지 로딩 시 500ms 최소 지연을 적용하고 있으나, 여기에는 없습니다. 빠른 네트워크에서 스켈레톤 깜빡임이 발생할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/mypage/SavePage.tsx` around lines 38 - 66, The savedFeeds and
savedBooks useInifinieScroll calls are missing the minLoadingTime pattern which
causes skeleton flicker on fast networks; update both useInifinieScroll
invocations (the ones that define fetchPage for getSavedFeedsInMy and
getSavedBooksInMy) to include a minLoadingTime option of 500 (apply it so it
affects initial load — i.e., when cursor is null/undefined) following the same
pattern used in Feed.tsx/Followers/SearchBook/Memory to ensure the first-page
loading shows at least 500ms.
src/pages/feed/FeedDetailPage.tsx (1)

137-145: ⚠️ Potential issue | 🟡 Minor

window.close()가 중복 호출됩니다.

Line 138에서 window.close()가 무조건 호출된 후, Line 141에서 다시 호출됩니다. 첫 번째 호출 이후 if/else 블록은 사실상 도달할 수 없는 코드입니다. 이 PR에서 도입된 변경은 아니지만, 의도한 동작은 window.opener가 있을 때만 window.close()하고 그렇지 않으면 navigate(-1)하는 것으로 보입니다.

🐛 수정 제안
 const handleBackClick = () => {
-  window.close();
-
   if (window.opener) {
     window.close();
   } else {
     navigate(-1);
   }
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/feed/FeedDetailPage.tsx` around lines 137 - 145, The
handleBackClick function currently calls window.close() unconditionally and
again inside the if block, making the first call redundant; update
handleBackClick so it only checks window.opener and calls window.close() when
window.opener is truthy, otherwise call navigate(-1). Locate the function by
name handleBackClick and adjust the conditional logic (referencing window.opener
and navigate) to remove the duplicate unconditional window.close() call.
src/pages/feed/Feed.tsx (1)

43-74: ⚠️ Potential issue | 🟡 Minor

fetchPage에 500ms 최소 로딩 시간이 없습니다.

다른 페이지들(FollowerListPage, SearchBook, Memory 등)은 첫 페이지 로딩 시 minLoadingTime(500ms)을 적용하여 스켈레톤이 너무 짧게 깜빡이는 것을 방지하고 있습니다. Feed.tsxtotalFeedmyFeedfetchPage에는 이 패턴이 빠져 있어, 빠른 네트워크 환경에서 스켈레톤이 순간적으로 깜빡일 수 있습니다.

Based on learnings, Feed 페이지 초기 로딩 지연은 500ms여야 합니다.

🔧 수정 제안 (totalFeed 예시, myFeed에도 동일 적용)
   const totalFeed = useInifinieScroll<PostData>({
     enabled: activeTab === '피드',
     reloadKey: activeTab,
     fetchPage: async cursor => {
       await waitForToken();
+      const minLoadingTime = cursor ? null : new Promise(resolve => setTimeout(resolve, 500));
       const response = await getTotalFeeds(cursor ? { cursor } : undefined);
+      if (minLoadingTime) await minLoadingTime;
       return {
         items: response.data.feedList,
         nextCursor: response.data.nextCursor || null,
         isLast: response.data.isLast,
       };
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/feed/Feed.tsx` around lines 43 - 74, The fetchPage implementations
in totalFeed and myFeed must enforce a 500ms minimum loading time for the
initial page load to prevent skeleton flicker: inside each fetchPage (in the
useInifinieScroll calls for totalFeed and myFeed) record start time before
awaiting waitForToken(), run the network request (getTotalFeeds/getMyFeeds) and
in parallel await a delay so that when cursor is falsy (initial load) the total
elapsed time is at least 500ms, then return the response as before; implement
the delay by computing remaining = 500 - (Date.now() - start) and awaiting a
sleep/timeout only if remaining > 0, leaving non-initial pages unchanged.
🧹 Nitpick comments (5)
src/pages/groupSearch/GroupSearch.tsx (2)

44-48: fetchRecentSearches가 useEffect 의존성 배열에 누락되었습니다.

Line 41의 마운트 effect에는 eslint-disable 주석이 있지만, 이 effect(Line 44-48)에서는 fetchRecentSearches를 호출하면서 의존성 배열에 포함하지 않았습니다. useCallback으로 감싸져 있어 현재는 안정적인 참조이지만, fetchRecentSearches를 의존성에 추가하는 것이 좋습니다.

♻️ 수정 제안
   useEffect(() => {
     if (searchStatus === 'idle') {
       fetchRecentSearches();
     }
-  }, [searchStatus]);
+  }, [searchStatus, fetchRecentSearches]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/groupSearch/GroupSearch.tsx` around lines 44 - 48, The effect that
calls fetchRecentSearches when searchStatus === 'idle' is missing
fetchRecentSearches from its dependency array; update the useEffect to include
fetchRecentSearches (i.e., useEffect(..., [searchStatus, fetchRecentSearches]))
and ensure the fetchRecentSearches function is memoized with useCallback (or
remains so) to provide a stable reference; also remove any eslint-disable
comment masking this dependency if present so the linter can validate the
dependency list.

139-141: reloadKeysearchStatus가 포함되어 있어 불필요한 재요청이 발생할 수 있습니다.

searchStatus'searching''searched'로 변경될 때 queryTerm도 함께 변경되면, reloadKeysearchStatusqueryTerm 두 값이 모두 바뀌면서 effect가 두 번 트리거될 수 있습니다. 또한 searchStatusisFinalized 파라미터에도 영향을 주므로, reloadKey에서 searchStatus를 제거하면 실제 검색 파라미터 변화에만 반응하도록 할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/groupSearch/GroupSearch.tsx` around lines 139 - 141, The reloadKey
currently includes searchStatus which causes redundant reloads when status flips
(e.g., 'searching'→'searched'); update the invocation of useInifinieScroll by
removing searchStatus from the reloadKey (keep
reloadKey=`${queryTerm}-${selectedFilter}-${category}`) so the effect only
reacts to actual search parameters, but leave the enabled logic (enabled:
searchStatus !== 'idle' && (searchStatus === 'searched' || !!queryTerm)) and any
isFinalized handling unchanged.
src/pages/mypage/SavePage.tsx (1)

118-191: 렌더링 로직의 중첩 삼항 연산자가 깊습니다.

showInitialLoading ? (...) : activeTab === '피드' ? (...) : savedBooks.items.length > 0 ? (...) : (...) 처럼 4단계 깊이의 삼항 연산자 체인은 가독성을 떨어뜨립니다. 각 조건별 렌더링을 별도 컴포넌트나 함수로 추출하면 유지보수성이 개선될 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/mypage/SavePage.tsx` around lines 118 - 191, The JSX uses a deeply
nested ternary (showInitialLoading ? ... : activeTab === '피드' ? ... :
savedBooks.items.length > 0 ? ... : ...) which hurts readability; refactor by
extracting each branch into small components or functions (e.g.,
LoadingSkeletons using FeedPostSkeleton and BookSkeletonItem, SavedFeedList
rendering savedFeeds.items with FeedPost and handleFeedSaveToggle, and
SavedBookList rendering savedBooks.items with Cover, BookInfo and
handleSaveToggle) and replace the ternary chain in SavePage's render with a
clear conditional (if/switch or direct component returns) that returns
LoadingSkeletons, SavedFeedList, SavedBookList, or EmptyState accordingly;
ensure you keep sentinelRef, isLoadingMore, keys (feed.feedId, book.bookId) and
props like isLast/isMyFeed when moving logic.
src/pages/memory/Memory.tsx (2)

207-221: 서버 필터링과 클라이언트 필터링이 중복됩니다.

fetchPage에서 이미 isOverview, pageStart, pageEnd, isPageFilter 파라미터를 API에 전달하여 서버 측에서 필터링하고 있습니다(Lines 114-120). 그런데 filteredRecords(Lines 207-221)에서 동일한 조건으로 다시 클라이언트 필터링을 수행하고 있습니다. 서버 응답이 이미 필터링된 데이터를 반환한다면 이 메모이제이션은 불필요한 연산입니다.

서버 필터링만으로 충분하다면 filteredRecords를 제거하고 recordsList.items를 직접 사용하는 것을 고려해주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/memory/Memory.tsx` around lines 207 - 221, The client-side
filtering in the useMemo named filteredRecords duplicates server-side filtering
done in fetchPage (parameters isOverview, pageStart, pageEnd, isPageFilter);
remove filteredRecords and replace its usages with recordsList.items (or change
the memo to simply return recordsList.items) so we rely on server-filtered
results; ensure any references to activeFilter/selectedPageRange that expected
client-side filtering are updated to trigger fetchPage instead and that UI logic
still behaves correctly.

143-151: Axios 에러 타입 체크가 취약합니다.

덕 타이핑으로 'response' in error를 확인하는 대신 axiosisAxiosError 유틸리티나 instanceof AxiosError를 사용하면 타입 안전성이 향상됩니다. 관련 코드 스니펫(getRoomPlaying.ts)에서도 instanceof AxiosError를 사용하고 있습니다.

♻️ 수정 제안
+      import { AxiosError } from 'axios';
       // ...
       } catch (error) {
-        if (error && typeof error === 'object' && 'response' in error) {
-          const axiosError = error as { response?: { data?: { code?: number } } };
-          if (axiosError.response?.data?.code === 40002) {
+        if (error instanceof AxiosError && error.response?.data?.code === 40002) {
             setActiveFilter(null);
             throw new Error('독서 진행률이 80% 이상이어야 총평을 볼 수 있습니다.');
-          }
         }
         throw new Error('기록을 불러오는 중 오류가 발생했습니다.');
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/memory/Memory.tsx` around lines 143 - 151, Replace the duck-typing
error check in the catch block of Memory.tsx with axios' type-safe check: import
and use axios.isAxiosError (or AxiosError instanceof) to determine if the thrown
error is an AxiosError, then inspect axiosError.response?.data?.code === 40002
and call setActiveFilter(null) and rethrow the specific 80% message; otherwise
rethrow the generic "기록을 불러오는 중 오류가 발생했습니다." error—update the catch branch that
currently uses "'response' in error" and the axiosError type assertion to use
the axios utility or AxiosError type for proper type safety.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/pages/feed/Feed.tsx`:
- Around line 43-74: The fetchPage implementations in totalFeed and myFeed must
enforce a 500ms minimum loading time for the initial page load to prevent
skeleton flicker: inside each fetchPage (in the useInifinieScroll calls for
totalFeed and myFeed) record start time before awaiting waitForToken(), run the
network request (getTotalFeeds/getMyFeeds) and in parallel await a delay so that
when cursor is falsy (initial load) the total elapsed time is at least 500ms,
then return the response as before; implement the delay by computing remaining =
500 - (Date.now() - start) and awaiting a sleep/timeout only if remaining > 0,
leaving non-initial pages unchanged.

In `@src/pages/feed/FeedDetailPage.tsx`:
- Around line 137-145: The handleBackClick function currently calls
window.close() unconditionally and again inside the if block, making the first
call redundant; update handleBackClick so it only checks window.opener and calls
window.close() when window.opener is truthy, otherwise call navigate(-1). Locate
the function by name handleBackClick and adjust the conditional logic
(referencing window.opener and navigate) to remove the duplicate unconditional
window.close() call.

In `@src/pages/mypage/SavePage.tsx`:
- Around line 38-66: The savedFeeds and savedBooks useInifinieScroll calls are
missing the minLoadingTime pattern which causes skeleton flicker on fast
networks; update both useInifinieScroll invocations (the ones that define
fetchPage for getSavedFeedsInMy and getSavedBooksInMy) to include a
minLoadingTime option of 500 (apply it so it affects initial load — i.e., when
cursor is null/undefined) following the same pattern used in
Feed.tsx/Followers/SearchBook/Memory to ensure the first-page loading shows at
least 500ms.

---

Nitpick comments:
In `@src/pages/groupSearch/GroupSearch.tsx`:
- Around line 44-48: The effect that calls fetchRecentSearches when searchStatus
=== 'idle' is missing fetchRecentSearches from its dependency array; update the
useEffect to include fetchRecentSearches (i.e., useEffect(..., [searchStatus,
fetchRecentSearches])) and ensure the fetchRecentSearches function is memoized
with useCallback (or remains so) to provide a stable reference; also remove any
eslint-disable comment masking this dependency if present so the linter can
validate the dependency list.
- Around line 139-141: The reloadKey currently includes searchStatus which
causes redundant reloads when status flips (e.g., 'searching'→'searched');
update the invocation of useInifinieScroll by removing searchStatus from the
reloadKey (keep reloadKey=`${queryTerm}-${selectedFilter}-${category}`) so the
effect only reacts to actual search parameters, but leave the enabled logic
(enabled: searchStatus !== 'idle' && (searchStatus === 'searched' ||
!!queryTerm)) and any isFinalized handling unchanged.

In `@src/pages/memory/Memory.tsx`:
- Around line 207-221: The client-side filtering in the useMemo named
filteredRecords duplicates server-side filtering done in fetchPage (parameters
isOverview, pageStart, pageEnd, isPageFilter); remove filteredRecords and
replace its usages with recordsList.items (or change the memo to simply return
recordsList.items) so we rely on server-filtered results; ensure any references
to activeFilter/selectedPageRange that expected client-side filtering are
updated to trigger fetchPage instead and that UI logic still behaves correctly.
- Around line 143-151: Replace the duck-typing error check in the catch block of
Memory.tsx with axios' type-safe check: import and use axios.isAxiosError (or
AxiosError instanceof) to determine if the thrown error is an AxiosError, then
inspect axiosError.response?.data?.code === 40002 and call setActiveFilter(null)
and rethrow the specific 80% message; otherwise rethrow the generic "기록을 불러오는 중
오류가 발생했습니다." error—update the catch branch that currently uses "'response' in
error" and the axiosError type assertion to use the axios utility or AxiosError
type for proper type safety.

In `@src/pages/mypage/SavePage.tsx`:
- Around line 118-191: The JSX uses a deeply nested ternary (showInitialLoading
? ... : activeTab === '피드' ? ... : savedBooks.items.length > 0 ? ... : ...)
which hurts readability; refactor by extracting each branch into small
components or functions (e.g., LoadingSkeletons using FeedPostSkeleton and
BookSkeletonItem, SavedFeedList rendering savedFeeds.items with FeedPost and
handleFeedSaveToggle, and SavedBookList rendering savedBooks.items with Cover,
BookInfo and handleSaveToggle) and replace the ternary chain in SavePage's
render with a clear conditional (if/switch or direct component returns) that
returns LoadingSkeletons, SavedFeedList, SavedBookList, or EmptyState
accordingly; ensure you keep sentinelRef, isLoadingMore, keys (feed.feedId,
book.bookId) and props like isLast/isMyFeed when moving logic.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8f9b157 and a6b1182.

📒 Files selected for processing (7)
  • src/pages/feed/Feed.tsx
  • src/pages/feed/FeedDetailPage.tsx
  • src/pages/feed/FollowerListPage.tsx
  • src/pages/groupSearch/GroupSearch.tsx
  • src/pages/memory/Memory.tsx
  • src/pages/mypage/SavePage.tsx
  • src/pages/searchBook/SearchBook.tsx

Copy link
Member

@ljh130334 ljh130334 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

충돌 많았을텐데 깔끔하게 작업해주셔서 감사합니다!! 넘 수고하셨습니다 👍🏻 🥇

Copy link
Collaborator

@ho0010 ho0010 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생 많으셨습니다!
확실히 로직을 분리하니 가독성 측면에서 크게 개선된 것 같네요~

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/feed/Feed.tsx (1)

8-16: ⚠️ Potential issue | 🔴 Critical

중복된 LoadingSpinner import를 제거하세요.

Line 8과 Line 16에서 동일한 LoadingSpinner 컴포넌트를 서로 다른 경로로 중복 import하고 있습니다. 이는 TypeScript 컴파일 오류를 발생시킵니다. Line 8의 상대 경로 import를 제거하고, Line 16의 @/ 경로 import만 유지하세요.

수정안
-import LoadingSpinner from '../../components/common/LoadingSpinner';
 import writefab from '../../assets/common/writefab.svg';
 import { useNavigate, useLocation } from 'react-router-dom';
 import { getTotalFeeds } from '@/api/feeds/getTotalFeed';
 import { getMyFeeds } from '@/api/feeds/getMyFeed';
 import { useSocialLoginToken } from '@/hooks/useSocialLoginToken';
 import { useFeedCache, writeFeedCache } from '@/hooks/useFeedCache';
 import { useInifinieScroll } from '@/hooks/useInifinieScroll';
 import LoadingSpinner from '@/components/common/LoadingSpinner';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/feed/Feed.tsx` around lines 8 - 16, Remove the duplicate
LoadingSpinner import: keep the alias import "import LoadingSpinner from
'@/components/common/LoadingSpinner';" and delete the relative import "import
LoadingSpinner from '../../components/common/LoadingSpinner';" so there is only
a single import of the LoadingSpinner component; ensure any references to
LoadingSpinner remain unchanged and run TypeScript build to verify no other
duplicate imports exist.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/groupSearch/GroupSearch.tsx`:
- Around line 135-153: The issue is that the fetch call in useInifinieScroll
passes debouncedSearchTerm while reloadKey and conditional logic use queryTerm,
causing mismatched requests; update the getSearchRooms invocation in the
fetchPage callback to use queryTerm (the trimmed term derived at top) instead of
debouncedSearchTerm so the API parameter, reloadKey, and search-status checks
(in useInifinieScroll / fetchPage / getSearchRooms) are consistent; verify the
other arguments (toSortKey(selectedFilter), category, isAllCategory) remain
unchanged.

---

Outside diff comments:
In `@src/pages/feed/Feed.tsx`:
- Around line 8-16: Remove the duplicate LoadingSpinner import: keep the alias
import "import LoadingSpinner from '@/components/common/LoadingSpinner';" and
delete the relative import "import LoadingSpinner from
'../../components/common/LoadingSpinner';" so there is only a single import of
the LoadingSpinner component; ensure any references to LoadingSpinner remain
unchanged and run TypeScript build to verify no other duplicate imports exist.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a6b1182 and 698aaa8.

📒 Files selected for processing (5)
  • src/pages/feed/Feed.tsx
  • src/pages/feed/FeedDetailPage.tsx
  • src/pages/groupSearch/GroupSearch.tsx
  • src/pages/memory/Memory.tsx
  • src/pages/searchBook/SearchBook.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/feed/FeedDetailPage.tsx

Comment on lines +135 to 153
const queryTerm = searchStatus === 'searched' ? searchTerm.trim() : debouncedSearchTerm.trim();
const isAllCategory = !queryTerm && category === '';

const searchResult = useInifinieScroll({
enabled: searchStatus !== 'idle' && (searchStatus === 'searched' || !!queryTerm),
reloadKey: `${searchStatus}-${queryTerm}-${selectedFilter}-${category}`,
fetchPage: async cursor => {
const isFinalized = searchStatus === 'searched';
const isAllCategory = !debouncedSearchTerm && category === '';
if (searchStatus === 'searching' && !queryTerm) {
return { items: [], nextCursor: null, isLast: true };
}

const minLoadingTime = cursor ? null : new Promise(resolve => setTimeout(resolve, 500));
const res = await getSearchRooms(
debouncedSearchTerm,
toSortKey(selectedFilter),
cursor ?? undefined,
isFinalized,
searchStatus === 'searched',
category,
isAllCategory,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

검색 API 파라미터가 reloadKey 기준과 불일치합니다.

Line 135/140에서 기준 쿼리는 queryTerm인데, Line 148은 debouncedSearchTerm을 사용합니다. 이 상태면 검색 확정 직후 첫 요청이 이전 키워드로 나갈 수 있습니다.

🔧 제안 수정안
       const res = await getSearchRooms(
-        debouncedSearchTerm,
+        queryTerm,
         toSortKey(selectedFilter),
         cursor ?? undefined,
         searchStatus === 'searched',
         category,
         isAllCategory,
       );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/groupSearch/GroupSearch.tsx` around lines 135 - 153, The issue is
that the fetch call in useInifinieScroll passes debouncedSearchTerm while
reloadKey and conditional logic use queryTerm, causing mismatched requests;
update the getSearchRooms invocation in the fetchPage callback to use queryTerm
(the trimmed term derived at top) instead of debouncedSearchTerm so the API
parameter, reloadKey, and search-status checks (in useInifinieScroll / fetchPage
/ getSearchRooms) are consistent; verify the other arguments
(toSortKey(selectedFilter), category, isAllCategory) remain unchanged.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/pages/feed/Feed.tsx (1)

112-119: TotalFeed 래핑 Fragment는 제거해도 됩니다.

현재 구간의 <>...</>는 단일 컴포넌트만 감싸고 있어 기능상 필요하지 않습니다. JSX 깊이를 줄이기 위해 제거를 권장합니다.

간단한 정리 diff
-          {activeTab === '피드' ? (
-            <>
-              <TotalFeed
-                showHeader={true}
-                posts={totalFeed.items}
-                isTotalFeed={true}
-                isLast={totalFeed.isLast}
-              />
-            </>
-          ) : (
+          {activeTab === '피드' ? (
+            <TotalFeed
+              showHeader={true}
+              posts={totalFeed.items}
+              isTotalFeed={true}
+              isLast={totalFeed.isLast}
+            />
+          ) : (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/feed/Feed.tsx` around lines 112 - 119, Remove the unnecessary React
fragment wrapping the single TotalFeed component in Feed.tsx: delete the
surrounding <> and </> around the TotalFeed JSX so that TotalFeed is rendered
directly (keep props: showHeader, posts, isTotalFeed, isLast intact); verify no
other siblings rely on that fragment and that JSX still compiles.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/pages/feed/Feed.tsx`:
- Around line 112-119: Remove the unnecessary React fragment wrapping the single
TotalFeed component in Feed.tsx: delete the surrounding <> and </> around the
TotalFeed JSX so that TotalFeed is rendered directly (keep props: showHeader,
posts, isTotalFeed, isLast intact); verify no other siblings rely on that
fragment and that JSX still compiles.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 698aaa8 and 79e2482.

📒 Files selected for processing (1)
  • src/pages/feed/Feed.tsx

@heeeeyong heeeeyong merged commit acb0847 into refactor Feb 27, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants